package session

import (
	"GeoORM/clause"
	"reflect"
)

//Insert 插入实体对象到表中,需要做实体对象属性到表列值的转换
func (s *Session) Insert(values ...interface{}) (int64, error) {
	recordValues := make([]interface{}, 0)
	//遍历每一个传入的对象
	for _, value := range values {
		//拿到当前实体对应的tableName
		table := s.Model(value).RefTable()
		//进行Insert子句的构建,多次调用不会产生影响,因此Set内部做了判断
		s.clause.Set(clause.INSERT, table.Name, table.FieldNames)
		//拼接实参值
		recordValues = append(recordValues, table.RecordValues(value))
	}
	//构建Values子句
	s.clause.Set(clause.VALUES, recordValues...)
	//构造完整的sql语句和对应的参数列表
	sql, vars := s.clause.Build(clause.INSERT, clause.VALUES)
	//执行sql语句
	result, err := s.Raw(sql, vars...).Exec()
	if err != nil {
		return 0, err
	}
	return result.RowsAffected()
}

//Find 传入实体对象的切片数组,然后查表将表记录转换为实体对象列表
func (s *Session) Find(values interface{}) error {
	//拿到指向values本身的value,而不是指向values指针的value
	destSlice := reflect.Indirect(reflect.ValueOf(values))
	//因为destSlice类型为切片,所有这里elem返回的是切片元素类型
	destType := destSlice.Type().Elem()
	//创建一个新的实体对象,对象属性由零值填充
	//解析该实体对象后,返回对应的Schema类型
	table := s.Model(reflect.New(destType).Elem().Interface()).RefTable()
	//构建select子句
	s.clause.Set(clause.SELECT, table.Name, table.FieldNames)
	//构建完整的sql语句
	sql, vars := s.clause.Build(clause.SELECT, clause.WHERE, clause.ORDERBY, clause.LIMIT)
	//执行sql语句
	rows, err := s.Raw(sql, vars...).QueryRows()
	if err != nil {
		return err
	}
	//挨个记录遍历
	for rows.Next() {
		//创建一个新对象实例
		dest := reflect.New(destType).Elem()
		//values数组存放所需要的字段
		var values []interface{}
		//遍历表字段
		for _, name := range table.FieldNames {
			//通过字段名去实体中寻找对应的字段
			//Addr是为了拿到变量的地址,而不是变量本身
			values = append(values, dest.FieldByName(name).Addr().Interface())
		}
		//scan传入的是变量的地址,变量顺序和数量需要与数据库列顺序和数量一致
		if err := rows.Scan(values...); err != nil {
			return err
		}
		//反射赋值
		destSlice.Set(reflect.Append(destSlice, dest))
	}
	return rows.Close()
}
